接下來要支援的就是 Multiple Page。和 streamlit 不太一樣的是,我是把 page nav list 擺在 navbar,主要是因為個人偏好。
不過這不是甚麼一定要的樣式,之後搞不好可以給讓 package 使用者設定。
每個頁面都由 PageConfig 結構來定義:
// PageConfig stores basic setting of a page
type PageConfig struct {
// Name should not duplicate to another page
Name string `json:"name"`
// Title will show as the title of page
Title string `json:"title"`
// Emoji will show as icon of a page
Emoji string `json:"emoji"`
}
Package 使用者可以使用 AddPageByConfig 方法來添加頁面:
app.AddPageByConfig(&framework.PageConfig{
Name: "page1",
Title: "Page1",
Emoji: "🐱",
}, Page1Func)
其中 App 是我們提供的一個新的介面,裡面存放 Page Func 和 Page Config,HTTP Server 可以跟 App 要到 Pages 的資料,然後 Expose 一個 /api/app
的 endpoint,提供以下格式的配置資料給前端:
{
# 按照順序的 page names
"page_names": [
"index",
"content",
# ...
],
"page_confs": {
"code": {
"name": "code",
"title": "Source Code",
"emoji": ""
},
"content": {
"name": "content",
"title": "Content",
"emoji": ""
},
# ...
}
}
實際上的關聯:
前端在載入時會向 /api/app
發送請求,獲取頁面配置資料。根據 URL 中的 pathname,前端可以確定當前頁面,並使用 rerun 機制更新頁面內容。
pageName = window.location.pathname.substring(1)
這樣前端在送 rerun 時,就可以把 page_name 帶進參數裡面,就可以做到 multipage 了。
附註:設置 Emoji 為 favicon (參考)
function faviconTemplate(icon: string) {
return `
<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22>
<text y=%22.9em%22 font-size=%2290%22>
${icon}
</text>
</svg>
`.trim();
}
export function setIcon(emoji: string) {
const iconEle = document.querySelector(`head > link[rel='icon']`) as Element
iconEle.setAttribute(`href`, `data:image/svg+xml,${faviconTemplate(emoji)}`)
}
if (curconf.emoji) {
setIcon(curconf.emoji)
}